﻿using AutoMapper;
using CK.Sprite.Cache;
using CK.Sprite.Framework;
using JetBrains.Annotations;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Data;
using System.Dynamic;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace CK.Sprite.Form.Core
{
    public class SpriteObjectService : DomainService
    {
        public ICacheSendNotice CacheSendNotice => LazyGetRequiredService(ref _cacheSendNotice);
        private ICacheSendNotice _cacheSendNotice;

        private string applicationCode;

        public SpriteObjectService()
        {
        }

        public async Task AddSpriteObjectAsync(SpriteObjectCreateDto spriteObjectCreateDto)
        {
            CommonConsts.CheckSqlInject(spriteObjectCreateDto.Name);
            CommonConsts.CheckSqlInject(spriteObjectCreateDto.RemoteSelect);
            CommonConsts.CheckSqlInject(spriteObjectCreateDto.UnionIndex);
            var spriteObjectDto = Mapper.Map<SpriteObjectCreateDto, SpriteObjectDto>(spriteObjectCreateDto);
            spriteObjectDto.ObjectPropertyDtos = Mapper.Map<List<ObjectPropertyCreateDto>, List<ObjectPropertyDto>>(spriteObjectCreateDto.ObjectPropertyCreateDtos);
            SetAddSpriteObjectId(spriteObjectDto);
            await _serviceProvider.DoDapperServiceAsync(DefaultDbConfig, async (unitOfWork) =>
            {
                SpriteObjectHandler spriteObjectHandler = _serviceProvider.GetService<SpriteObjectHandler>();
                ObjectPropertyHandler objectPropertyHandler = _serviceProvider.GetService<ObjectPropertyHandler>();
                var businessDbHandler = _serviceProvider.GetService<BusinessDbHandler>();

                spriteObjectHandler.SetNext(objectPropertyHandler, unitOfWork);
                objectPropertyHandler.SetNext(businessDbHandler, unitOfWork);
                businessDbHandler.SetNext(null, unitOfWork);

                await spriteObjectHandler.AddSpriteObjectAsync(spriteObjectDto);
            });
            CacheSendNotice.SendClearCache($"{CommonConsts.SpriteFormCachePreKey}-{applicationCode}_{CommonConsts.SpriteObjectCacheKey}");
        }

        public async Task UpdateSpriteObject(SpriteObjectUpdateDto spriteObjectUpdateDto)
        {
            CommonConsts.CheckSqlInject(spriteObjectUpdateDto.RemoteSelect);
            await _serviceProvider.DoDapperServiceAsync(DefaultDbConfig, async (unitOfWork) =>
            {
                var spriteObjectRepository = ConnectionFactory.GetConnectionProvider(DefaultDbConfig.ConnectionType).GetRepository<ISpriteObjectRepository>(unitOfWork);

                var spriteObject = await spriteObjectRepository.GetAsync(spriteObjectUpdateDto.Id);
                if (spriteObject == null)
                {
                    throw new SpriteException("未找到spriteObject数据信息");
                }
                Mapper.Map(spriteObjectUpdateDto, spriteObject);

                await spriteObjectRepository.UpdateAsync(spriteObject);

                applicationCode = spriteObject.ApplicationCode;
            });
            CacheSendNotice.SendClearCache($"{CommonConsts.SpriteFormCachePreKey}-{applicationCode}_{CommonConsts.SpriteObjectCacheKey}");
        }

        public async Task<List<SpriteObject>> GetListSpriteObjectAsync(string applicationCode = "Default", int? keyType = null, string filter = default, string category = default)
        {
            return await _serviceProvider.DoDapperServiceAsync(DefaultDbConfig, async (unitOfWork) =>
            {
                var spriteCommonRepository = ConnectionFactory.GetConnectionProvider(DefaultDbConfig.ConnectionType).GetRepository<ISpriteCommonRepository>(unitOfWork);
                ExpressSqlModel expressSqlModel = new ExpressSqlModel()
                {
                    SqlExpressType = ESqlExpressType.And,
                    Children = new List<ExpressSqlModel>()
                     {
                         new ExpressSqlModel()
                         {
                            Field = "ApplicationCode",
                            ConditionType = EConditionType.等于,
                            Value = applicationCode,
                            SqlExpressType = ESqlExpressType.Condition
                         }
                     }
                };
                if(keyType.HasValue)
                {
                    expressSqlModel.Children.Add(new ExpressSqlModel()
                    {
                        Field = "KeyType",
                        ConditionType = EConditionType.等于,
                        Value = keyType.Value,
                        SqlExpressType = ESqlExpressType.Condition
                    });
                }
                if (!string.IsNullOrEmpty(category))
                {
                    expressSqlModel.Children.Add(new ExpressSqlModel()
                    {
                        Field = "Category",
                        ConditionType = EConditionType.等于,
                        Value = category,
                        SqlExpressType = ESqlExpressType.Condition
                    });
                }
                if (!string.IsNullOrEmpty(filter))
                {
                    expressSqlModel.Children.Add(new ExpressSqlModel()
                    {
                        SqlExpressType = ESqlExpressType.Or,
                        Children = new List<ExpressSqlModel>()
                         {
                             new ExpressSqlModel()
                             {
                                Field = "Name",
                                ConditionType = EConditionType.Like,
                                Value = filter,
                                SqlExpressType = ESqlExpressType.Condition
                             },
                             new ExpressSqlModel()
                             {
                                Field = "Description",
                                ConditionType = EConditionType.Like,
                                Value = filter,
                                SqlExpressType = ESqlExpressType.Condition
                             },
                         }
                    });
                }
                var result = await spriteCommonRepository.GetCommonList2<SpriteObject>("SpriteObjects", expressSqlModel);
                return result;
            });
        }

        public async Task<List<string>> GetCategorysAsync()
        {
            return await _serviceProvider.DoDapperServiceAsync(DefaultDbConfig, async (unitOfWork) =>
            {
                var spriteFormRepository = ConnectionFactory.GetConnectionProvider(DefaultDbConfig.ConnectionType).GetRepository<ISpriteObjectRepository>(unitOfWork);
                return await spriteFormRepository.GetCategorysAsync("SpriteObjects");
            });
        }

        #region ObjectProperty Operate

        public async Task AddObjectProperty(ObjectPropertyCreateDto objectPropertyCreateDto)
        {
            CommonConsts.CheckSqlInject(objectPropertyCreateDto.Name);
            var objectProperty = Mapper.Map<ObjectPropertyCreateDto, ObjectProperty>(objectPropertyCreateDto);
            objectProperty.Id = Guid.NewGuid();

            await _serviceProvider.DoDapperServiceAsync(DefaultDbConfig, async (unitOfWork) =>
            {
                var objectPropertyRepository = new GuidRepositoryBase<ObjectProperty>(unitOfWork);
                var spriteObjectRepository = ConnectionFactory.GetConnectionProvider(DefaultDbConfig.ConnectionType).GetRepository<ISpriteObjectRepository>(unitOfWork);

                var objectPropertyHandler = _serviceProvider.GetService<ObjectPropertyHandler>();
                var spriteObjectHandler = _serviceProvider.GetService<SpriteObjectHandler>();
                var businessDbHandler = _serviceProvider.GetService<BusinessDbHandler>();

                objectPropertyHandler.SetNext(spriteObjectHandler, unitOfWork);
                spriteObjectHandler.SetNext(businessDbHandler, unitOfWork);
                businessDbHandler.SetNext(null, unitOfWork);

                var spriteObject = await spriteObjectHandler.GetSpriteObject(objectPropertyCreateDto.ObjectId);

                await objectPropertyHandler.AddObjectProperty(objectProperty, objectPropertyRepository);
                await spriteObjectHandler.ChangeObjectProperty(objectProperty.ObjectId, spriteObjectRepository);

                await businessDbHandler.AddObjectProperty(objectProperty, spriteObject.Name, spriteObject.ApplicationCode);

                applicationCode = spriteObject.ApplicationCode;
            });
            CacheSendNotice.SendClearCache($"{CommonConsts.SpriteFormCachePreKey}-{applicationCode}_{CommonConsts.SpriteObjectCacheKey}");
        }

        public async Task UpdateObjectProperty(ObjectPropertyUpdateDto objectPropertyUpdateDto)
        {
            await _serviceProvider.DoDapperServiceAsync(DefaultDbConfig, async (unitOfWork) =>
            {
                var objectPropertyRepository = new GuidRepositoryBase<ObjectProperty>(unitOfWork);
                var spriteObjectRepository = ConnectionFactory.GetConnectionProvider(DefaultDbConfig.ConnectionType).GetRepository<ISpriteObjectRepository>(unitOfWork);

                var objectProperty = await objectPropertyRepository.GetAsync(objectPropertyUpdateDto.Id);
                if (objectProperty == null)
                {
                    throw new SpriteException("未找到ObjectProperty数据信息");
                }
                Mapper.Map(objectPropertyUpdateDto, objectProperty);

                var objectPropertyHandler = _serviceProvider.GetService<ObjectPropertyHandler>();
                var spriteObjectHandler = _serviceProvider.GetService<SpriteObjectHandler>();
                var businessDbHandler = _serviceProvider.GetService<BusinessDbHandler>();

                objectPropertyHandler.SetNext(spriteObjectHandler, unitOfWork);
                spriteObjectHandler.SetNext(businessDbHandler, unitOfWork);
                businessDbHandler.SetNext(null, unitOfWork);

                var spriteObject = await spriteObjectHandler.GetSpriteObject(objectProperty.ObjectId);

                await objectPropertyHandler.UpdateObjectProperty(objectProperty, objectPropertyRepository);
                await spriteObjectHandler.ChangeObjectProperty(objectProperty.ObjectId, spriteObjectRepository);

                await businessDbHandler.ModifyObjectProperty(objectProperty, spriteObject.Name, spriteObject.ApplicationCode);

                applicationCode = spriteObject.ApplicationCode;
            });
            CacheSendNotice.SendClearCache($"{CommonConsts.SpriteFormCachePreKey}-{applicationCode}_{CommonConsts.SpriteObjectCacheKey}");
        }

        public async Task DeleteObjectProperty(Guid id)
        {
            await _serviceProvider.DoDapperServiceAsync(DefaultDbConfig, async (unitOfWork) =>
            {
                var objectPropertyRepository = new GuidRepositoryBase<ObjectProperty>(unitOfWork);
                var spriteObjectRepository = ConnectionFactory.GetConnectionProvider(DefaultDbConfig.ConnectionType).GetRepository<ISpriteObjectRepository>(unitOfWork);

                var deleteData = await objectPropertyRepository.GetAsync(id);
                if (deleteData == null)
                {
                    throw new SpriteException("未找到ObjectProperty数据信息");
                }

                var objectPropertyHandler = _serviceProvider.GetService<ObjectPropertyHandler>();
                var spriteObjectHandler = _serviceProvider.GetService<SpriteObjectHandler>();
                var businessDbHandler = _serviceProvider.GetService<BusinessDbHandler>();

                objectPropertyHandler.SetNext(spriteObjectHandler, unitOfWork);
                spriteObjectHandler.SetNext(businessDbHandler, unitOfWork);
                businessDbHandler.SetNext(null, unitOfWork);

                var spriteObject = await spriteObjectHandler.GetSpriteObject(deleteData.ObjectId);

                await objectPropertyHandler.DeleteObjectProperty(deleteData, objectPropertyRepository);
                await spriteObjectHandler.ChangeObjectProperty(deleteData.ObjectId, spriteObjectRepository);

                await businessDbHandler.DeleteObjectProperty(deleteData.Name, spriteObject.Name, spriteObject.ApplicationCode);

                applicationCode = spriteObject.ApplicationCode;
            });
            CacheSendNotice.SendClearCache($"{CommonConsts.SpriteFormCachePreKey}-{applicationCode}_{CommonConsts.SpriteObjectCacheKey}");
        }

        public async Task<List<ObjectProperty>> GetListObjectPropertyAsync(Guid objectId)
        {
            return await _serviceProvider.DoDapperServiceAsync(DefaultDbConfig, async (unitOfWork) =>
            {
                var spriteCommonRepository = ConnectionFactory.GetConnectionProvider(DefaultDbConfig.ConnectionType).GetRepository<ISpriteCommonRepository>(unitOfWork);
                List<QueryWhereModel> queryWhereModels = new List<QueryWhereModel>()
                {
                    new QueryWhereModel()
                    {
                        Field = "ObjectId",
                        ConditionType = EConditionType.等于,
                        Value = objectId
                    }
                };
                var result = await spriteCommonRepository.GetCommonList<ObjectProperty>("ObjectPropertys", queryWhereModels);
                return result;
            });
        }

        #endregion

        #region ObjectMethod Operate

        public async Task AddObjectMethodAsync(ObjectMethodCreateDto objectMethodCreateDto)
        {
            var objectMethod = Mapper.Map<ObjectMethodCreateDto, ObjectMethod>(objectMethodCreateDto);
            objectMethod.Id = Guid.NewGuid();

            await _serviceProvider.DoDapperServiceAsync(DefaultDbConfig, async (unitOfWork) =>
            {
                var objectMethodRepository = new GuidRepositoryBase<ObjectMethod>(unitOfWork);

                applicationCode = objectMethodCreateDto.ApplicationCode;
                return await objectMethodRepository.InsertAsync(objectMethod);
            });
            CacheSendNotice.SendClearCache($"{CommonConsts.SpriteFormCachePreKey}-{applicationCode}_{CommonConsts.ObjectMethodCacheKey}");
        }

        public async Task UpdateObjectMethodAsync(ObjectMethodUpdateDto objectMethodUpdateDto)
        {
            await _serviceProvider.DoDapperServiceAsync(DefaultDbConfig, async (unitOfWork) =>
            {
                var objectMethodRepository = new GuidRepositoryBase<ObjectMethod>(unitOfWork);
                var objectMethod = await objectMethodRepository.GetAsync(objectMethodUpdateDto.Id);
                if (objectMethod == null)
                {
                    throw new SpriteException("未找到ObjectMethod数据信息");
                }
                Mapper.Map(objectMethodUpdateDto, objectMethod);
                applicationCode = objectMethod.ApplicationCode;
                return await objectMethodRepository.UpdateAsync(objectMethod);
            });
            CacheSendNotice.SendClearCache($"{CommonConsts.SpriteFormCachePreKey}-{applicationCode}_{CommonConsts.ObjectMethodCacheKey}");
        }

        public async Task DeleteObjectMethod(Guid id)
        {
            await _serviceProvider.DoDapperServiceAsync(DefaultDbConfig, async (unitOfWork) =>
            {
                GuidRepositoryBase<ObjectMethod> objectMethodRepository = new GuidRepositoryBase<ObjectMethod>(unitOfWork);
                var deleteData = await objectMethodRepository.GetAsync(id);
                if (deleteData == null)
                {
                    throw new SpriteException("未找到ObjectMethod数据信息");
                }
                await objectMethodRepository.DeleteAsync(deleteData);

                applicationCode = deleteData.ApplicationCode;
            });
            CacheSendNotice.SendClearCache($"{CommonConsts.SpriteFormCachePreKey}-{applicationCode}_{CommonConsts.ObjectMethodCacheKey}");
        }

        public async Task<List<ObjectMethod>> GetListObjectMethodAsync(Guid objectId)
        {
            return await _serviceProvider.DoDapperServiceAsync(DefaultDbConfig, async (unitOfWork) =>
            {
                var spriteCommonRepository = ConnectionFactory.GetConnectionProvider(DefaultDbConfig.ConnectionType).GetRepository<ISpriteCommonRepository>(unitOfWork);
                List<QueryWhereModel> queryWhereModels = new List<QueryWhereModel>()
                {
                    new QueryWhereModel()
                    {
                        Field = "ObjectId",
                        ConditionType = EConditionType.等于,
                        Value = objectId
                    }
                };
                var result = await spriteCommonRepository.GetCommonList<ObjectMethod>("ObjectMethods", queryWhereModels);
                return result;
            });
        }

        #endregion

        //// 计算路径
        //private void SetAddCommonParams(SpriteObjectCreateDto spriteObjectCreateDto)
        //{
        //    foreach(var objectMethodCreateDto in spriteObjectCreateDto.ObjectMethodCreateDtos)
        //    {
        //        var commonParamCreateDtos = new List<CommonParamCreateDto>();
        //        foreach (var commonParamCreateDto in objectMethodCreateDto.CommonParamCreateDtos)
        //        {
        //            commonParamCreateDto.TreePath = commonParamCreateDto.ParamName;
        //            commonParamCreateDtos.Add(commonParamCreateDto);
        //            if(commonParamCreateDto.Children != null && commonParamCreateDto.Children.Count > 0)
        //            {
        //                SetChildCommonParams(commonParamCreateDtos, commonParamCreateDto);
        //            }
        //        }

        //        objectMethodCreateDto.CommonParamCreateDtos = commonParamCreateDtos;
        //    }
        //}

        //private void SetChildCommonParams(List<CommonParamCreateDto> commonParamCreateDtos,  CommonParamCreateDto parentCommonCreateDto)
        //{
        //    foreach(var childCommonCreateDto in parentCommonCreateDto.Children)
        //    {
        //        childCommonCreateDto.TreePath = parentCommonCreateDto.TreePath + ":" + childCommonCreateDto.ParamName;
        //        commonParamCreateDtos.Add(childCommonCreateDto);
        //        if (childCommonCreateDto.Children != null && childCommonCreateDto.Children.Count > 0)
        //        {
        //            SetChildCommonParams(commonParamCreateDtos, childCommonCreateDto);
        //        }
        //    }
        //}

        // 设置实体Guid
        private void SetAddSpriteObjectId(SpriteObjectDto spriteObjectDto)
        {
            var tempSpriteObjectId = Guid.NewGuid();
            spriteObjectDto.Id = tempSpriteObjectId;
            foreach (var objectPropertyDto in spriteObjectDto.ObjectPropertyDtos)
            {
                var tempObjectPropertyId = Guid.NewGuid();
                objectPropertyDto.Id = tempObjectPropertyId;
                objectPropertyDto.ObjectId = tempSpriteObjectId;
            }

            spriteObjectDto.Version = Guid.NewGuid();
        }
    }
}
